Padding,Stride,Channels

Note

padding,stride,channels都是卷积运算的参数,有了它们我们能更好地控制卷积运算

Padding

观察前一节的运算我们可以注意到,边缘像素参与的卷积运算次数会比中心像素更少,这在某种程度上丢失了边缘像素的信息。

为了修正这一点,我们在input外层人为地加若干圈0,目的是让所有像素参与的运算次数一致,这就是padding。

jupyter

假设我们上下各填充 \(p_{h}\) 行,左右各填充 \(p_{w}\) 列, 那么输出的shape:

\[(n_{h} - k_{h} + 2*p_{h} + 1)\times(n_{w} - k_{w} + 2*p_{w} + 1)\]

\(k_{h},k_{w}\) 为奇数,我们可以令 \(p_{h} = \frac{k_{h} - 1}{2}, p_{w} = \frac{k_{w} - 1}{2}\) 使得输入和输出的shape相同。

Stride

jupyter

相邻subset的信息是差不多的,为了减少冗余的运算,我们可以一次跨越多个格。

stride即一次跨多少个格,假设我们一次横跨 \(s_{w}\) 格,纵跨 \(s_{h}\) 格,那么输出的shape:

\[\left \lfloor\frac{n_{h} - k_{h} + 2*p_{h} + 1}{s_{h}} \right \rfloor\times\left \lfloor \frac{n_{w} - k_{w} + 2*p_{w} + 1}{s_{w}} \right \rfloor\]

Channels

每个 RGB 彩色图片的shape: \(3\times{h}\times{w}\).

在图像处理中,除了长、宽,还有通道这个维度。kernel的通道数必须和input的通道数相同,结果还是对应元素相加再相乘:

jupyter

有几个kernel,输出的通道数就是几:

jupyter

import torch
import torch.nn.functional as F

# (batch_size, in_channel, in_h, in_w)
inputs = torch.rand(1, 3, 9, 9)
# (out_channel, in_channel, kernel_h, kernel_w)
kernels = torch.rand(2, 3, 3, 3)

output的高和宽:

\[\left \lfloor\frac{9 - 3 + 2*1 + 1}{3} \right \rfloor\times\left \lfloor \frac{9 - 3 + 2*1 + 1}{3} \right \rfloor = 3\times{3}\]
output = F.conv2d(inputs, kernels, padding=1, stride=3)
# as expected
output.shape
torch.Size([1, 2, 3, 3])